<?php

define("FRM_DB_DSN", "mysql:dbname=catalogue2;host=localhost|martin:gaspo");
$GLOBALS['FRM_DB_OPTIONS']=array();
$GLOBALS['FRM_DB_INIT_STATEMENTS'] = array();
$GLOBALS['FRM_DB_INIT_STATEMENTS'][]='SET NAMES "utf8"';

/**
* DB abstraction layer
*
* @author Stan
*
* @version 2.1
*/
class myDB
{
	private $myDB;
  
  /**
  * makes connection
  *
  * @param mixed $dsn_string
  * @param mixed $options
  * @return my_DB
  */
  function __construct($dsn_string, $options=array(), $init_statements=array())
  {
  	if(empty($in_dsn_string))
      $in_dsn_string = FRM_DB_DSN;
    
    if (empty($in_dsn_string))
    	return new frm_error(FRM_ERROR_UNDER_MAINTENANCE,"can't connect to DB, dns string not given.");
  	
    if (!defined('DB_ONE'))
    {
      define('DB_ONE', 1);
      define('DB_ALL', 2);
      define('DB_COL', 3);
      define('DB_ROW', 4);
      define('DB_QUERY', 5);
      define('DB_ASSOC', 6);
      define('DB_AUTOQUERY_INSERTUPDATE',10);
      define('DB_AUTOQUERY_INSERT',20);
      define('DB_AUTOQUERY_UPDATE',30);
      
    }
    if (!defined('FRM_FATAL_ERROR_REDIR_URL'))
      define('FRM_FATAL_ERROR_REDIR_URL',"error.html");

    //set exception mode
    $options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
    $options[PDO::ATTR_CASE] = PDO::CASE_LOWER;
      
    try {
    	  $conPar = explode("|",$in_dsn_string);
    	  $conAccess=explode(":",$conPar[1]);
          $dbh = new PDO($conPar[0], $conAccess[0],$conAccess[1],$options);
          $this->myDB=$dbh;
          //prepare init statements
          if (!empty($init_statements))
            foreach ($init_statements as $sql) {
              $this->myDB->exec($sql);
            }
		} catch (PDOException $e) {
		    return new frm_error(FRM_ERROR_UNDER_MAINTENANCE,"can't connect to DB:".$e->getMessage());
		}
    
  }
  
  /**
   *
   * funtion returns already created or new instance of myBD
   * @param string $dsn_string
   * @param array $options
   * @return myDB
   */
  public static function singleton($dsn_string, $options=null, $init_statements=null)
  {
    static $myDB;
    if(!is_a($myDB, 'myDB'))
    {
    
	    try {
	    	$myDB = new myDB($dsn_string, $options, $init_statements);
	    	
	    	if(frm_error::isError($myDB))
	    		throw new frm_error(ERROR_UNEXPECTED,"db creation exception:".$myDB->system_message);
	    	
	      general::debug("DB connection established");
	    }
	    
	    catch (PDOException $e)
	    {
	    	return new frm_error(ERROR_UNEXPECTED,"db creation exception:".$e->getMessage());
	    }
          
    }
    
    return $myDB;
  }
  

  
  
  /**
  * call original methods on PDO if is not overloaded in this class
  *
  * @param mixed $name
  * @param mixed $arguments
  * @return mixed
  */
  public function __call($name, $arguments)
  {
    try
    {
      return call_user_func_array(array($this->myDB, $name), $arguments);
    }
    catch (PDOException $e)
    {
      return new frm_error(ERROR_UNEXPECTED,"autoexect PDO exception:".$e->getMessage());
    }
  }
  
  /**
  * compatibitiy class
  * executes automatically array of data
  * @param string $in_table
  * @param array $in_data
  * @param integer $in_mode
  * @param string $in_where
  * @param boolean $flag_encode
  * @return integer number of affected rows
  */
  public function autoExecute($in_table, $in_data, $in_mode = DB_AUTOQUERY_INSERT, $in_where = false, $flag_encode = true)
  {
  	
  	try
  	{
	  	if (empty($in_data))
	  		return;
	  		
	  	if (empty($in_table))
	  		return new frm_error(ERROR_UNEXPECTED,"autoexec table not defined");
	  	
	    /*if($flag_encode === true)
	      foreach($in_data as &$value)
	      {
	        $value = htmlspecialchars($value, ENT_QUOTES, 'utf-8', false);
	      }*/
	      
	    general::debug('autoExecute: '.$in_table.' '.$in_mode, $in_data);
	    
	    if ($in_mode==DB_AUTOQUERY_INSERT)
	    {
	    	$names = "";
	    	$values = "";
	    	foreach ($in_data as $k => $v)
	    	{
	    		$names.="`$k`,";
	    		$values.=":$k,";
	    	}
	    	
	    	$sql = "INSERT INTO `$in_table` (".substr($names,0,-1).") VALUES (".substr($values,0,-1).")";
	    }
	    elseif ($in_mode==DB_AUTOQUERY_UPDATE)
	    {
	    	if (empty($in_where))
	    		return new frm_error(ERROR_UNEXPECTED, "autorexec update key to update not given");
	    	 
	    	$names = "";
	    	foreach ($in_data as $k => $v)
	    		$names.="`$k`=:$k,";
	
	    	
	    	$sql = "UPDATE `$in_table` SET ".substr($names,0,-1)." WHERE $in_where";
	    	
	    }
	    elseif($in_mode == DB_AUTOQUERY_INSERTUPDATE) // insert .. on duplicate key update
	    {
	    	$names = $values = $names_values = "";
	    	foreach ($in_data as $k => $v)
	    	{
	    		$names.="`$k`,";
	    		$values.=":$k,";
	    		$names_values.="`$k`=:$k,";
	    	}
	    	
	    	$sql = "INSERT INTO `$in_table` (".substr($names,0,-1).") VALUES (".substr($values,0,-1).")
	    	        ON DUPLICATE KEY
	    	        UPDATE ".substr($names_values,0,-1);
	     
	    }
	    else
	      return new frm_error(ERROR_UNEXPECTED, "autoexec db mode:>$in_mode< unsupported.");
    
      general::debug("autoexec SQL",$sql);
   		//execute prepared statements
   		$sth = $this->myDB->prepare($sql);
   		$affected_rows = $sth->execute($in_data);
   		
	    return $affected_rows;
	      
  	}
    catch (PDOException $e)
    {
    	return new frm_error(ERROR_UNEXPECTED,"autoexect PDO exception:".$e->getMessage());
    }
  }
  
  /**
   * returns all data as associative array
   * @param string $in_sql sql query to execute or prepare
   * @param array $in_data optional data to complete prepared statement
   * @return array
   * @return frm_error
   */
  public function getAll($in_sql,$in_data=array())
  {
  	if (empty($in_sql))
  		return new frm_error(ERROR_UNEXPECTED, "getall: no sql query given");

    try {
    	$sth = $this->myDB->prepare($in_sql);
			$sth->execute($in_data);
			return $sth->fetchAll(PDO::FETCH_ASSOC);
    }
    catch (PDOException $e)
    {
    	return new frm_error(ERROR_UNEXPECTED, "getAll exception:".$e->getMessage());
    }
  		
  }
  
  /**
   * returns data of one column as indexed array
   * @param string $in_sql sql query to execute or prepare
   * @param array $in_data optional data to complete prepared statement
   * @return array
   * @return frm_error
   */
  public function getCol($in_sql,$in_data=array())
  {
  	if (empty($in_sql))
  		return new frm_error(ERROR_UNEXPECTED, "getCol: no sql query given");

    try {
    	$sth = $this->myDB->prepare($in_sql);
			$sth->execute($in_data);
			return $sth->fetchAll(PDO::FETCH_COLUMN,0);
    }
    catch (PDOException $e)
    {
    	return new frm_error(ERROR_UNEXPECTED, "getCol exception:".$e->getMessage());
    }
  		
  }
  
	/**
   * returns data of one record as associative array
   * @param string $in_sql sql query to execute or prepare
   * @param array $in_data optional data to complete prepared statement
   * @return array
   * @return frm_error
   */
  public function getRow($in_sql,$in_data=array())
  {
  	if (empty($in_sql))
  		return new frm_error(ERROR_UNEXPECTED, "getRow: no sql query given");

    try {
    	$sth = $this->myDB->prepare($in_sql);
			$sth->execute($in_data);
			return $sth->fetch(PDO::FETCH_ASSOC);
    }
    catch (PDOException $e)
    {
    	return new frm_error(ERROR_UNEXPECTED, "getRow exception:".$e->getMessage());
    }
  		
  }
  
	/**
   * returns data of one value
   * @param string $in_sql sql query to execute or prepare
   * @param array $in_data optional data to complete prepared statement
   * @return string
   * @return frm_error
   */
  public function getOne($in_sql,$in_data=array())
  {
  	if (empty($in_sql))
  		return new frm_error(ERROR_UNEXPECTED, "getRow: no sql query given");

    try {
    	$sth = $this->myDB->prepare($in_sql);
			$sth->execute($in_data);
			$res = $sth->fetch(PDO::FETCH_NUM);
			if (is_array($res) && !empty($res))
				return $res[0];
			else
				return null;
    }
    catch (PDOException $e)
    {
    	return new frm_error(ERROR_UNEXPECTED, "getRow exception:".$e->getMessage());
    }
  		
  }
  
  
  public function getAssoc($in_sql,$in_data=array())
  {
    if (empty($in_sql))
      return new frm_error(ERROR_UNEXPECTED, "getAssoc: no sql query given");

    try {
      $sth = $this->myDB->prepare($in_sql);
      $sth->execute($in_data);
      $cols = $sth->fetchAll(PDO::FETCH_ASSOC);
      $result=array();
      foreach($cols as $row)
      {
        $count = 1;
        foreach($row as $value)
        {
          if($count==1)
            $key = $value;
          else
            $result[$key]=$value;
          $count++;
        }
      }
      general::debug("getAssocRes", $result);
      return $result;
    }
    catch (PDOException $e)
    {
      return new frm_error(ERROR_UNEXPECTED, "getAssoc exception:".$e->getMessage());
    }
      
  }
  
}

?>